#include "cmdmapinfo.h"
#include "../mainctrl.h"
#include "../cmd/dataprepare.h"
#include "../map/CMapView.h"
#include "commmsg.h"

#include "MsgMapInfo.pb.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_GET_MAP_INFO , CCmdGetMapInfo);

int CCmdGetMapInfo::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_GET_MAP_INFO ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Tpye=%d",
            ID_MAIN_GET_MAP_INFO,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    unsigned int uiGID = stReq.gid();
    CT_TRACE(("get map info %u", uiGID));

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    bHasGetMapUsers = false;

    LogicDo(RET_OK);
    return RET_OK;
}

int CCmdGetMapInfo::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, stReq.gid());
    ASSERT_PLAYER_PREPARED(stReq.gid());
    PREPARE_PLAYER_ONLINE_DATA(this, stReq.gid());

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return Done(RET_NO_USER);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //准备地图用户数据
    if (stPlayerOnlineData._uiNowMapID > 9000000) //此种地图不需要转发，只用保存
    {
        return Done(RET_OK);
    }

    if (!bHasGetMapUsers)
    {
        //准备地图上的用户数据
        iRet = pstMainCtrl->m_stMapViews.GetMapUsers(stPlayerOnlineData._uiNowMapID, stPlayerBaseInfo._uiGID, astMapUsers);
        if (iRet != 0)
        {
            CT_WARNING(("GetMapUsers error, ret %d", iRet));
            return AnsClients(iRet);
        }
    }

    for (int i = 0; i < astMapUsers.Size(); ++i)
    {
        PREPARE_PLAYER_BASE_INFO(this, astMapUsers[i]);
        PREPARE_PLAYER_DETAIL_INFO(this, astMapUsers[i]);
    }

    _uiMapID = stPlayerOnlineData._uiNowMapID;

    return AnsClients(RET_OK);
}

int CCmdGetMapInfo::AnsClients(int iRet)
{
    if (iRet != 0)
    {
        return Done(iRet);
    }

    /*
    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return Done(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];
    */

    /*
    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return Done(RET_NO_USER);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    if (stPlayerOnlineData._uiNowMapID > 9000000) //此种地图不需要转发，只用保存
    {
        return Done(iRet);
    }
    */

    /*
    //返回地图上的其他用户信息
    CSingleMapView::MAP_VIEW_NOTIFY_USERS_ARRAY astMapUsers;
    iRet = pstMainCtrl->m_stMapViews.GetMapUsers(stPlayerOnlineData._uiNowMapID, stPlayerBaseInfo._uiGID, astMapUsers);
    if (iRet != 0)
    {
        CT_WARNING(("GetMapUsers error, ret %d", iRet));
        return Done(iRet);
    }
    */

    stMsgHead.set_msgret(RET_OK);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    for (int i = 0; i < astMapUsers.Size(); ++i)
    {
        /*
        if (astMapUsers[i] == (unsigned int)stReq.gid())
        {
            continue;
        }
        */

        int iIndexTemp = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(astMapUsers[i]);
        if (iIndexTemp < 0)
        {
            continue;
        }
        CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndexTemp];

        iIndexTemp = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(astMapUsers[i]);
        if (iIndexTemp < 0)
        {
            continue;
        }
        CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndexTemp];

        iIndexTemp = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(astMapUsers[i]);
        if (iIndexTemp < 0)
        {
            continue;
        }
        CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndexTemp];

        iIndexTemp = pstMainCtrl->m_stPlayerSnsCommInfoHash.HashFind(astMapUsers[i]);
        if (iIndexTemp < 0)
        {
            CT_ERROR(("no user %u", astMapUsers[i]));
            continue;
        }
        CPlayerSnsCommInfo& stPlayerSnsCommInfo = pstMainCtrl->m_stPlayerSnsCommInfoHash[iIndexTemp];

        iIndexTemp = CMainCtrl::m_pstMain->FindPlayerCacheData(astMapUsers[i]);
        if (iIndexTemp < 0)
        {
            CT_ERROR(("no user %u", astMapUsers[i]));
            continue;
        }
        CPlayerCacheData& stPlayerCache = CMainCtrl::m_pstMain->m_stPlayerCacheDataHash[iIndexTemp];

        MsgAnsMapInfo stAnsMapInfo;
        stAnsMapInfo.set_gid(astMapUsers[i]);

        pstMainCtrl->m_stStatusMgr.GetUserStatusAndTitle(stPlayerBaseInfo,
            stPlayerDetailInfo, stPlayerOnlineData, stPlayerCache,
            stPlayerSnsCommInfo, stAnsMapInfo, true);

        MsgAnsUserStorageInfo* pstMsgAnsUserStorageInfo = stAnsMapInfo.mutable_equip();
        pstMainCtrl->m_stEquipMgr.GetEquipInfo(stPlayerDetailInfo, stPlayerOnlineData, 0, *pstMsgAnsUserStorageInfo);

        pstMainCtrl->m_stEncodeBuf.Clear();
        pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
        pstMainCtrl->EncodePBMsg(stAnsMapInfo, pstMainCtrl->m_stEncodeBuf);

        if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
        {
            CT_WARNING((""));
            return Done(RET_SYS_ERROR);
        }
    }

    //一战到底活动特殊处理:进入地图可能触发战斗开启
    if (pstMainCtrl->m_stFightEndMgr.GetMapID() == _uiMapID)
    {
        pstMainCtrl->m_stFightEndMgr.TriggerBattle();
    }

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
CT_REGISTER_ASYNCCMD(ID_MAIN_MAP_MOVE , CCmdMapMoveTo);

int CCmdMapMoveTo::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_MAP_MOVE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Tpye=%d",
            ID_MAIN_MAP_MOVE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    unsigned int uiGID = stReq.gid();
    CT_TRACE(("move to info %u", uiGID));

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return RET_OK;
}

int CCmdMapMoveTo::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, stReq.gid());
    ASSERT_PLAYER_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_EX1_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_EX1_INFO(stReq.gid());

    PREPARE_PLAYER_SNS_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_SNS_DETAIL_PREPARED(stReq.gid());

    PREPARE_PLAYER_ONLINE_DATA(this, stReq.gid());

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        stPlayerBaseInfo._uiMapID = stReq.map_id();
        stPlayerBaseInfo._usXPos = (unsigned short)stReq.pos_x();
        stPlayerBaseInfo._usYPos = (unsigned short)stReq.pos_y();

        //更新数据
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);

        return Done(RET_OK);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo & stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        CT_ERROR(("no detail ex1 data user(%u)", stReq.gid()));
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1 =
        pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no online data", stReq.gid()));
        return AnsClients(RET_NO_USER);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    iIndex = pstMainCtrl->FindPlayerCacheData(stReq.gid());
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no cache data", stReq.gid()));
        return AnsClients(RET_NO_USER);
    }
	CPlayerCacheData& stPlayerCache = pstMainCtrl->m_stPlayerCacheDataHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerSnsCommInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        CT_ERROR(("online user %u has no sns comm data", stReq.gid()));
        return AnsClients(RET_NO_USER);
    }
    CPlayerSnsCommInfo& stPlayerSnsCommInfo = pstMainCtrl->m_stPlayerSnsCommInfoHash[iIndex];

    _uiNewMapID = (unsigned int)stReq.map_id();

    //登陆的时候,前台会发送MoveTo到当前位置的请求. 对于这个请求,不要取消冥想状态
    if ((stReq.pos_x() != stPlayerBaseInfo._usXPos || stReq.pos_y() != stPlayerBaseInfo._usYPos || _uiNewMapID != stPlayerBaseInfo._uiMapID) 
        && stPlayerDetailInfo._stMuseData.IsMusing())
    {
        pstMainCtrl->m_stMuseMgr.StopMuseAndNotify(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    }

    //加入家族当天需要禁止,进入家族大厅地图
    if (MAP_ID_CLAN_HALL == _uiNewMapID)
    {
#ifdef _DEBUG
        if (stPlayerDetailInfo._stUserClan._uiClanId > 0             
            && pstMainCtrl->m_stMagicDoorMgr.GetCheckJoinDay()
            && stPlayerDetailInfo._stUserClan.HasJoinedClanBefore()
            && CTTimeUtils::IsSameDay(pstMainCtrl->m_iNow, stPlayerDetailInfo._stUserClan._iJoinTime, 0))
        {
            return AnsClients(ERROR_ENTER_HALL_TIME);
        }
#else
        if (stPlayerDetailInfo._stUserClan._uiClanId > 0 
            && stPlayerDetailInfo._stUserClan.HasJoinedClanBefore()
            && CTTimeUtils::IsSameDay(pstMainCtrl->m_iNow, stPlayerDetailInfo._stUserClan._iJoinTime, 0))
        {
            return AnsClients(ERROR_ENTER_HALL_TIME);
        }
#endif
    }

    //保存数据    
    if (stPlayerOnlineData._uiNowMapID != _uiNewMapID)
    {
        _bIsChgMap = true;
        _usNewPosX = (unsigned short)stReq.pos_x();
        _usNewPosY = (unsigned short)stReq.pos_y();
    }
    else
    {
        _bIsChgMap = false;
        _usNewPosX = (unsigned short)stReq.pos_x();
        _usNewPosY = (unsigned short)stReq.pos_y();
    }

    //todo: 地图移动校验
    if (_bIsChgMap)
    {
        //怪物攻城战
        iRet = pstMainCtrl->m_stEnemyAtkCityMgr.EnterScene(stReq.gid(), _uiNewMapID);
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }

        //世界BOSS
        iRet = pstMainCtrl->m_stWorldBossMgr.EnterScene(_uiNewMapID,
            (unsigned int)stReq.gid());
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }

        //学院BOSS
        iRet = pstMainCtrl->m_stAcademyBossMgr.EnterScene(_uiNewMapID,
            stPlayerBaseInfo);
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }

        //一战到底
        iRet = pstMainCtrl->m_stFightEndMgr.EnterScene(_uiNewMapID,
            _usNewPosX, _usNewPosY, stPlayerBaseInfo, stPlayerOnlineData);
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }

        //领地战
        iRet = pstMainCtrl->m_stManorBattleMgr.EnterScene(_uiNewMapID,
            _usNewPosX, _usNewPosY, stPlayerDetailInfo);
        if (iRet != 0)
        {
            return AnsClients(iRet);
        }

    }
    else
    {
        //角色移动时候相隔一定时间如果状态有变化则下发
        CMainCtrl::m_pstMain->m_stStatusMgr.UpdateUserStatus(stPlayerBaseInfo,
            stPlayerDetailInfo, stPlayerOnlineData, stPlayerCache,
            stPlayerSnsCommInfo, stPlayerDetailEx1, MAX_STATUS_UPDATE_TIME_GAP);

        //在一战到底地图内部限制变换位置
        if (pstMainCtrl->m_stFightEndMgr.GetMapID() == _uiNewMapID)
        {
            return AnsClients(ERROR_FIGHT_END_CAN_NOT_MOVE);
        }
    }

    _uiOrgMapID = stPlayerOnlineData._uiNowMapID;
    stPlayerOnlineData._uiNowMapID = _uiNewMapID;
    stPlayerOnlineData._usMapPosX = _usNewPosX;
    stPlayerOnlineData._usMapPosY = _usNewPosY;

    stAns.set_gid(stPlayerBaseInfo._uiGID);
    stAns.set_map_id(_uiNewMapID);
    stAns.set_pos_x(_usNewPosX == 0xFFFF ? -1 : _usNewPosX);
    stAns.set_pos_y(_usNewPosY == 0xFFFF ? -1 : _usNewPosY);

    return AnsClients(RET_OK);
}

int CCmdMapMoveTo::AnsClients(int iRet)
{
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    stMsgHead.set_msgret(iRet);

    if (RET_OK != iRet)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);
    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    //获取用户信息
    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return Done(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    //保存数据
    if (pstMainCtrl->m_stWorldBossMgr.IsMapIDNeedUpdateDB(_uiNewMapID)
        && pstMainCtrl->m_stAcademyBossMgr.IsMapIDNeedUpdateDB(_uiNewMapID)
        && MAX_ENEMY_ATK_CITY_MAP_ID != _uiNewMapID
        && MAP_ID_CLAN_HALL != _uiNewMapID
        && MAP_ID_AUCTION != _uiNewMapID
        && MAP_ID_INS != _uiNewMapID
        && pstMainCtrl->m_stFightEndMgr.GetMapID() != _uiNewMapID
        && pstMainCtrl->m_stManorBattleMgr.IsMapIDNeedUpdateDB(_uiNewMapID))
    {
        stPlayerBaseInfo._uiMapID = _uiNewMapID;
        stPlayerBaseInfo._usXPos =  _usNewPosX;
        stPlayerBaseInfo._usYPos =  _usNewPosY;

        //更新数据
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }

    //通知用户
    if (_bIsChgMap)        //切换地图
    {
        //离开通知
        CSingleMapView::MAP_VIEW_NOTIFY_USERS_ARRAY astNotifyUsers;
        iRet = pstMainCtrl->m_stMapViews.LeaveMap(_uiOrgMapID, stPlayerBaseInfo._uiGID, astNotifyUsers);
        if (iRet != 0)
        {
            CT_WARNING(("Move error, ret %d", iRet));
            return Done(iRet);
        }

        if (_uiOrgMapID < MIN_MAP_ID_NEED_NOT_SYNC)
        {
            for (int i = 0; i < astNotifyUsers.Size(); ++i)
            {
                if (astNotifyUsers[i] != (unsigned int)stReq.gid())
                {
                    pstMainCtrl->NotifyOnlineUser(astNotifyUsers[i], pstMainCtrl->m_stEncodeBuf);
                }
            }
        }
        
        //进入通知
        if (pstMainCtrl->m_stFightEndMgr.GetMapID() == _uiNewMapID ||
            pstMainCtrl->m_stManorBattleMgr.IsManorBattleScene(_uiNewMapID))
        {
            iRet = pstMainCtrl->m_stMapViews.IntoMap(
                _uiNewMapID, stPlayerBaseInfo._uiGID, false, _usNewPosX,
                _usNewPosY);
        }
        else
        {
            iRet = pstMainCtrl->m_stMapViews.IntoMap(
                _uiNewMapID, stPlayerBaseInfo._uiGID, false, stReq.pos_x(),
                stReq.pos_y());
        }

        if (iRet != 0)
        {
            CT_WARNING(("IntoMap %d", iRet));
        } 
    }
    else
    {
        if (_uiNewMapID > MIN_MAP_ID_NEED_NOT_SYNC) //此种地图不需要转发，只用保存
        {
            return Done(iRet);
        }

        //在一战到底地图内部限制变换位置
        if (pstMainCtrl->m_stFightEndMgr.GetMapID() == _uiNewMapID)
        {
            return Done(iRet);
        }

        //通知地图上的其他用户
        CSingleMapView::MAP_VIEW_NOTIFY_USERS_ARRAY astNotifyUsers;
        iRet = pstMainCtrl->m_stMapViews.Move(_uiNewMapID, stPlayerBaseInfo._uiGID,
            _usNewPosX, _usNewPosY, astNotifyUsers);
        if (iRet != 0)
        {
            CT_WARNING(("Move error, ret %d", iRet));
            return Done(iRet);
        }

        for (int i = 0; i < astNotifyUsers.Size(); ++i)
        {
            if (astNotifyUsers[i] != (unsigned int)stReq.gid())
            {
                pstMainCtrl->NotifyOnlineUser(astNotifyUsers[i], pstMainCtrl->m_stEncodeBuf);
            }
        }
    }

    pstMainCtrl->FlushSendCache();

    return Done(iRet);
}
